/*
 * phc -- the open source PHP compiler
 * See doc/license/README.license for licensing information
 *
 * Generate C code
 *
 */

#ifndef PHC_GENERATE_C
#define PHC_GENERATE_C

#include "MIR_visitor.h"
#include "codegen/MICG_gen.h"
#include "pass_manager/Pass.h"
#include <fstream>

class Generate_C : public MIR::Visitor, virtual public GC_obj
{
	std::ostream& os;
public:
	Generate_C (std::ostream&);

	/* TODO: os is not written into until post_php_script. There should be
	 * another way to flush its contents early, rather than accesing body
	 * directly. */
	stringstream body;

public:
	void children_statement (MIR::Statement* in);
	void pre_php_script (MIR::PHP_script* in);
	void post_php_script (MIR::PHP_script* in);

public:
	String* extension_name;
	bool is_extension;

	MICG_gen micg;

public:
	string compile_statement(MIR::Statement* in);
	void compile_static_value(string result, std::ostream& os, MIR::Static_value* sv);
};

using namespace boost;
using namespace MIR;
using namespace std;


string get_non_st_name (String* var_name);
string get_non_st_name (MIR::VARIABLE_NAME* var_name);
string prefix (string str, string prefix);

enum Scope { LOCAL, GLOBAL };
string get_scope (Scope scope);
string get_hash (String* name);
string get_st_entry (Scope scope, string zvp, MIR::VARIABLE_NAME* var_name);
string read_rvalue (string zvp, MIR::Rvalue* rvalue);
void function_declaration_block(ostream& buf, MIR::Signature_list* methods, String* block_name);
string attr_mod_flags(Attr_mod* mod);
string init_stats () ;
string finalize_stats ();
string increment_stat (string name);
void phc_unsupported (Node* node, const char* feature);

// TODO this is here for constant pooling. This should not be global.
extern struct gengetopt_args_info args_info;
string read_file (String* filename);
void include_file (ostream& out, String* filename);

string write_literal_directly_into_zval (string, Literal*);

string read_var_var (string zvp, string index);
string get_var_var (Scope scope, string zvp, string index);
string read_var (string zvp, VARIABLE_NAME* var_name);
string get_st_entry (Scope scope, string zvp, VARIABLE_NAME* var_name);
string read_rvalue (string zvp, Rvalue* rvalue);
string get_non_st_name (VARIABLE_NAME* var_name);
string get_non_st_name (String* var_name);
string prefix (string str, string prefix);
string suffix (string str, string suffix);
string get_hash (VARIABLE_NAME* name);
string cb_is_literal (Object_list* params);
string cb_get_length (Object_list* params);
string cb_get_hash (Object_list* params);
string cb_write_literal_directly_into_zval (Object_list* params);

class Pattern : virtual public GC_obj
{
public:
  Pattern ();
  virtual bool match(MIR::Statement* that) = 0;
  virtual void generate_code(Generate_C* gen) = 0;
  virtual ~Pattern();
  string generate (String* comment, Generate_C* gen);

 protected:
  bool use_scope;
  stringstream buf;  

};
//class VARIABLE_NAME;
//class MIR::VARIABLE_NAME;





/*
 * Helper functions
 */




/*
 * Map of the Zend functions that implement the operators
 *
 * The map also contains entries for ++ and --, which are identical to the
 * entries for + and -, but obviously need to be invoked slightly differently.
 */

static class Op_functions : public Map<string,string>
{
public:
	Op_functions() : Map<string,string>()
	{
		// Binary functions
		(*this)["+"] = "add_function";	
		(*this)["-"] = "sub_function";	
		(*this)["*"] = "mul_function";	
		(*this)["/"] = "div_function";	
		(*this)["%"] = "mod_function";	
		(*this)["xor"] = "boolean_xor_function";
		(*this)["|"] = "bitwise_or_function";
		(*this)["&"] = "bitwise_and_function";
		(*this)["^"] = "bitwise_xor_function";
		(*this)["<<"] = "shift_left_function";
		(*this)[">>"] = "shift_right_function";
		(*this)["."] = "concat_function";
		(*this)["=="] = "is_equal_function";
		(*this)["==="] = "is_identical_function";
		(*this)["!=="] = "is_not_identical_function";
		(*this)["!="] = "is_not_equal_function";
		(*this)["<"] = "is_smaller_function";
		(*this)["<="] = "is_smaller_or_equal_function";
		// Unary functions
		(*this)["!"] = "boolean_not_function";
		(*this)["not"] = "boolean_not_function";
		(*this)["~"] = "bitwise_not_function";
		// Post- functions
		(*this)["++"] = "increment_function";
		(*this)["--"] = "decrement_function";
	}
} op_functions;


string
write_literal_directly_into_zval (string var, Literal* lit);

void
init_method_record (ostream& buf, string obj, string name, string& fci_name, string& fcic_name, string ht, Node* node);

void
init_function_record (ostream& buf, string name, string& fci_name, string& fcic_name, Node* node);


#define INST(BUF, NAME, ...)						\
	do								\
	{								\
		Object* __obj_array[] = {__VA_ARGS__};			\
		Object_list* __obj_list = new Object_list;		\
									\
		foreach (Object* __obj, __obj_array)			\
			__obj_list->push_back (__obj);			\
									\
		BUF << gen->micg.instantiate (NAME, __obj_list);	\
	} while (0)							\


#endif // PHC_GENERATE_C
